package collision;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;

import java.awt.event.MouseAdapter;
import java.util.ArrayList;

import javax.swing.JPanel;
import javax.swing.Timer;


public class Board extends JPanel implements ActionListener{

	private static final long serialVersionUID = 1L;
	private Timer timer;
    private Craft craft;
    private Castle castle;
    private ArrayList<Shootable> aliens;
    private ArrayList<Shootable> birds;
    private int gamePoints;
    private int totalEnimiesKilled;
    private int totalBirdsKilled;
    
    private boolean ingame;
    private int B_WIDTH;
    private int B_HEIGHT;
    private boolean gameOver;
    private boolean startStage = true;
    private boolean inStageMenu = true;
    
    private final int POWER_BAR_COST = 1500;
    private final int FORTIFY_COST = 3000;
    private final int DOUBLE_FIRE_COST = 3000;
    private final int QUICK_FIRE_COST = 4000;
    
    
    private int stage;
    ArrayList<Button> buttons;


    /**
     * Initializes the entire game
     *
     * @param  wave  the starting wave
     * @param  points the starting points
     */
    public Board(int wave, int points) {

        addKeyListener(new TAdapter());
        addMouseListener(new CraftAdapter());

        
        setFocusable(true);
        setBackground(new Color(74,165, 255));
        
        setDoubleBuffered(true);
        ingame = false;
        gameOver = false;
        startStage=true;

        setSize(700, 500);
        stage = wave;
        gamePoints = points;
        totalEnimiesKilled = 0;
        totalBirdsKilled = 0;
        craft = new Craft();
        castle = new Castle();

        initEnemies();
        initButtons();

        timer = new Timer(1, this);
        timer.start();
        //timer.setDelay(1);

    }

    public void addNotify() {
        super.addNotify();
        B_WIDTH = getWidth();
        B_HEIGHT = getHeight();   
    }
    
    
    
    /**
     * Intiates all buttons for the game and puts them in an ArrayList
     */
    public void initButtons(){
    	buttons = new ArrayList<Button>();
    	//String s = "Buy Full Health.     $$: " + castle.fullHealthCost();
    	String t = "Fortify Castle ++100.     $$: " + FORTIFY_COST;
        Button play = new Button(Color.GREEN, 250, 150, 200, 120, "Play!", 80);
        Button buyHealth = new Button(Color.GRAY, 50, 200, 240, 50, "Buy Full Health.     $$: " + castle.fullHealthCost(), 15);
        Button buyMaxHealth = new Button(Color.GRAY, 50, 275, 240, 50, t, 15);
        Button buyPowerBar = new Button(Color.GRAY, 400, 200, 250, 50, "Eliminate power Bar     $$: "+POWER_BAR_COST, 15);
        Button buyDoublePower = new Button(Color.GRAY, 400, 275, 250, 50, "Buy double fire           $$: "+DOUBLE_FIRE_COST, 15);
        Button buyQuickFire = new Button(Color.GRAY, 400, 350, 250, 50, "Buy quick fire          $$: "+QUICK_FIRE_COST, 15);
        
        
        buttons.add(play);
        buttons.add(buyHealth);
        buttons.add(buyMaxHealth);
        buttons.add(buyPowerBar);
        buttons.add(buyDoublePower);
        buttons.add(buyQuickFire);
    }

    /**
     * Initiates the Shootable enemies in the game and puts them in an array list
     */
    public void initEnemies() {
    	//int num = (int)(10*(1+stage/5));
    	int num = (int)(Math.pow(stage, 2)/4 + 5);
    	int l = stage*150+2000;
    	EnemyWave alienWave;
    	if(!craft.canDoubleFire())
    		alienWave = new EnemyWave(400, 300, l, num);
    	else 
    		alienWave = new EnemyWave(420, 280, l, num);

    	EnemyWave birdWave = new EnemyWave(200, 10, 3000, 5);


    	birds = birdWave.getBirds();
        aliens = alienWave.getAliens();
    }


    /** 
     *  This is the main paint method for the game all other paint methods are run in this one.
     *  
     * @param  g the graphics component used to paint elements of the game
     */
    public void paint(Graphics g) {
    	
    	
    	super.paint(g);

        if (ingame) 
        {
        	if(inStageMenu && stage!=1)
        	{
        			paintStageStart(g);
        			craft.getMissiles().clear();
        	}
        	else if(startStage)
        		paintStageLabel(g);
        	else
        		paintInGameFrame(g);
        } 
        else if(gameOver)
        {
        	g.clearRect(0, 0, 1000, 1000);
        	String msg = "Game Over";

            Font small = new Font("Helvetica", Font.BOLD, 30);
            FontMetrics metr = this.getFontMetrics(small);

            g.setColor(Color.white);
            g.setFont(small);
            g.drawString(msg, (B_WIDTH - metr.stringWidth(msg)) / 2,
                         B_HEIGHT / 2);
        }
        else 
        {
            super.paint(g);
            g.setColor(Color.GREEN);
            g.fillRect(0, 0, 700, 700);
            g.setColor(new Color(74,165, 255));
            g.fillRect(20, 20, 660, 440);
            
            
            Button b = buttons.get(0);
            paintButton(g, b);
            
            if(buttons.get(0).clicked)
            	ingame=true;
            
            
            Font f = new Font("Helvetica", Font.BOLD, 90);
            //FontMetrics metr = this.getFontMetrics(f);
            g.setColor(Color.white);
            g.setFont(f);
            g.drawString("Arrow Eclipse", 30, 90);
            
            f = new Font("Helvetica", Font.BOLD, 17);
            //metr = this.getFontMetrics(f);
            g.setColor(Color.white);
            g.setFont(f);
            g.drawString("Directions: ", 30, 330);
            
            f = new Font("Helvetica", Font.PLAIN, 12);
           // metr = this.getFontMetrics(f);
            g.setColor(Color.white);
            g.setFont(f);
            g.drawString("WASD or arrow keys to move.", 30, 350);
            g.drawString("Hold mouse to charge power and release to shoot in the direction of the mouse.", 30, 365);
            g.drawString("Buy health and upgrades at the end of each level to keep your castle standing.", 30, 380);
            g.drawString("If the gray men get buy you they will damage your castle.  Birds do no damage but shooting them yeilds extra points.", 30, 395);
            

            
             
        }

        Toolkit.getDefaultToolkit().sync();
        g.dispose();
    }//end paint()
    
    
    /**
     * This paints the menu at the start of the page.  Just a large text displaying what stage is about to start. 
     *
     * @param  g  the graphics componenet used to paint various elements of the stage
     */
    public void paintStageStart(Graphics g)
    {
   	 	g.setColor(Color.GREEN);
   	 	g.fillRect(0, 250, 700, 400);
   	 	//Graphics2D g2d = (Graphics2D)g;

   	 	
   	 	int c = 150;
   	 	Font font = new Font("Helvetica", Font.BOLD, 25);
   	 	//FontMetrics metr = this.getFontMetrics(font);
   	 	g.setFont(font);
       	
   	 	g.setColor(Color.WHITE);
   	 	g.drawString("Stage "+stage+" complete", c, 40);

   	 	g.drawString("Castle Health: "+castle.getHealth()+" / "+ castle.getMaxHealth(), c, 70);
   	 	g.drawString("Points/Cash: "+gamePoints, c, 100);
   	 	
   	 	
   	 	font = new Font("Helvetica", Font.BOLD, 15);
   	 	//metr = this.getFontMetrics(font);
   	 	g.setFont(font);
   	 	
   	 	c = 500;
   	 	g.drawString("Total enimies killed: "+ totalEnimiesKilled, c, 20);
   	 	g.drawString("Total birds killed: "+ totalBirdsKilled, c, 40);

    	String s = "Buy Full Health.     Cost: " + castle.fullHealthCost();
   	 	buttons.get(1).setLabel(s);
   	 	paintButton(g, buttons.get(1));
   	 	
   	 	if(buttons.get(1).isClicked())
   	 	{

   	 			if(gamePoints >= castle.fullHealthCost())
   	 			{
   					buttons.get(1).setClicked(false);

   	 				gamePoints -= castle.fullHealthCost();
   	 				castle.addHealth(castle.getMaxHealth());
   	 			}
   	 			else if(gamePoints>0)
   	 			{
   					buttons.get(1).setClicked(false);
   					castle.addHealth(gamePoints/2);
   	 				gamePoints = 0;
   	 			}
   	 			else
   	 			{
		 	   	 	font = new Font("Helvetica", Font.PLAIN, 100);
		 	   	 	//metr = this.getFontMetrics(font);
		 	   	 	g.setFont(font);
		 	   	 	g.setColor(Color.RED);
		 	   	 	g.drawString("$", 100, 250);
   	 			}
   	 	}
   	 	
   	 	paintButton(g, buttons.get(2));
   	 	
   	 	if(buttons.get(2).isClicked() )
	 	{
				//buttons.get(2).setClicked(false);

	 			if(gamePoints >= FORTIFY_COST)
	 			{
					buttons.get(2).setClicked(false);

	 				//buttons.get(1).setClicked(true);
	 				gamePoints -= FORTIFY_COST;
	 				
	 				castle.addToMaxHealth(100);
	 			}
	 			else
	 			{
		 	   	 	font = new Font("Helvetica", Font.PLAIN, 100);
		 	   	 	//metr = this.getFontMetrics(font);
		 	   	 	g.setFont(font);
		 	   	 	g.setColor(Color.RED);
		 	   	 	g.drawString("$", 100, 340);
		 		}
	 	}
   	 	
   	 	paintButton(g, buttons.get(3));
   	 	if(craft.usesPowerBar())
   	 	{
	   	   	 	
	   	   	 	if(buttons.get(3).isClicked())
	   	   	 	{
   	   	 			buttons.get(3).setClicked(true);

	   	   	 		if(gamePoints >= POWER_BAR_COST)
	   	   	 		{
	   	   	 			gamePoints-=POWER_BAR_COST;
	   	   	 			craft.hasPowerBar(false);
	   	   	 			//buttons.remove(3);
	   	   	 		}
	   	   	 		else	   	   	 		
	   	   	 		{
	   	   	 			font = new Font("Helvetica", Font.PLAIN, 100);
	   	   	 			//metr = this.getFontMetrics(font);
	   	   	 			g.setFont(font);
	   	   	 			g.setColor(Color.RED);
	   	   	 			g.drawString("$", 450, 250);
	   	   	 		}
	   	   	 	}
	 			
   	 	}
   	 	
   	 	
   	 	paintButton(g, buttons.get(4));
   	 	if(!craft.canDoubleFire())
   	 	{
	   	   	 	
	   	   	 	if(buttons.get(4).isClicked())
	   	   	 	{
   	   	 			//buttons.get(4).setClicked(true);

	   	   	 		if(gamePoints >= DOUBLE_FIRE_COST)
	   	   	 		{
	   	   	 			gamePoints-=DOUBLE_FIRE_COST;
	   	   	 			craft.setDoubleFire(true);
	   	   	 		}
	   	   	 		else	   	   	 		
	   	   	 		{
	   	   	 			font = new Font("Helvetica", Font.PLAIN, 100);
	   	   	 			//metr = this.getFontMetrics(font);
	   	   	 			g.setFont(font);
	   	   	 			g.setColor(Color.RED);
	   	   	 			g.drawString("$", 450, 320);
	   	   	 		}
	   	   	 	}
	 			
   	 	}
   	 	
   	 	
   	 	paintButton(g, buttons.get(5));
   	 	if(!craft.getQuickFire())
   	 	{
	   	   	 	
	   	   	 	if(buttons.get(5).isClicked())
	   	   	 	{
   	   	 			//buttons.get(4).setClicked(true);

	   	   	 		if(gamePoints >= QUICK_FIRE_COST)
	   	   	 		{
	   	   	 			gamePoints-=QUICK_FIRE_COST;
	   	   	 			craft.setQuickFire(true);
	   	   	 		}
	   	   	 		else	   	   	 		
	   	   	 		{
	   	   	 			font = new Font("Helvetica", Font.PLAIN, 100);
	   	   	 			//metr = this.getFontMetrics(font);
	   	   	 			g.setFont(font);
	   	   	 			g.setColor(Color.RED);
	   	   	 			g.drawString("$", 450, 400);
	   	   	 		}
	   	   	 	}
	 			
   	 	}
   	 	
   	 	
   	 	font = new Font("Helvetica", Font.PLAIN, 50);
   	 	//metr = this.getFontMetrics(font);
   	 	g.setFont(font);
   	 	g.setColor(Color.BLACK);

     
   	 	g.drawString("(space to continue)", 100, 450);
    	
    }
    
    
    /**
     * This paints the title at the start of the page.  Just a large text displaying what stage is about to start. 
     *
     * @param  g  the graphics componenet used to paint various elements of the stage
     */
    public void paintStageLabel(Graphics g)
    {
    	
    	 g.setColor(Color.GREEN);
         g.fillRect(0, 250, 700, 400);
         Graphics2D g2d = (Graphics2D)g;

         Font font = new Font("Helvetica", Font.BOLD, 25);
         //FontMetrics metr = this.getFontMetrics(font);
         g.setFont(font);
           	

         g2d.drawImage(castle.getImage(), castle.getX(), castle.getY(), this);
         g.setColor(Color.RED);
         g.drawString("+ "+castle.getHealth(), 65, 365);
             
         

         g2d.drawImage(craft.getImage(), craft.getX(), craft.getY(), this);
         
         
         font = new Font("Helvetica", Font.BOLD, 120);
         //metr = this.getFontMetrics(font);
         g.setFont(font);

         g.setColor(Color.WHITE);
         g.drawString("Stage: "+ stage, 100, 250);
         
         font = new Font("Helvetica", Font.PLAIN, 15);
        // metr = this.getFontMetrics(font);
         g.setFont(font);
         g.drawString("(space to start)", 400, 290);
         

         
     	
    }
    
    /**
     * Each frame of the main game. 
     *
     * @param  g  the graphics componenet used to paint various elements of the stage
     */
    public void paintInGameFrame(Graphics g)
    {
    	g.setColor(Color.YELLOW);
    	g.fillOval(300, 300, 100, 100);
        g.setColor(Color.GREEN);
        
        g.fillRect(0, 250, 700, 400);
    	
    	//g.fillRect(0, 250, 700, 400);

        Graphics2D g2d = (Graphics2D)g;
        

       	Font font;

       	
        if (castle.isVisible())
        {
            g2d.drawImage(castle.getImage(), castle.getX(), castle.getY(), this);
        }
        

        
        ArrayList<Missile> ms = craft.getMissiles();
        
        	           	

        font = new Font("Helvetica", Font.BOLD, 14);

       	g.setColor(Color.GRAY);
       	g.setFont(font);
       	
        g.setColor(Color.BLACK);
        int arrowLenght = 15;
        for (int i = 0; i < ms.size(); i++) {
            Missile m = (Missile)ms.get(i);
            Vector2D d = m.getVector();
            g.drawLine(m.getX(), m.getY(), (int)(m.getX()+d.x*arrowLenght), (int)(m.getY()+d.y*arrowLenght));  
        }
        
        for (int i = 0; i < aliens.size(); i++) {
            Alien a = (Alien)aliens.get(i);
            if (a.isVisible())
                g2d.drawImage(a.getImage(), a.getX(), a.getY(), this);
        }

        if(craft.usesPowerBar())
        {
        	//draw power bar
            int rx=70;
            int ry=320;
           	g2d.setColor(Color.BLACK);
           	g2d.fillRect(rx, ry, 63, 11);
           	g2d.setColor(Color.RED);
           	g2d.fillRect(rx+1, ry+2, -craft.getPower()*7, 7 ); 
        }
        
        if (craft.isVisible())
        {
        	g2d.setColor(Color.black);
        	g2d.setStroke(new BasicStroke(3));
            int x0 = (int) craft.getBounds().getCenterX();
            int y0 = (int) craft.getBounds().getCenterY();
            Vector2D vect = craft.getArmVector();
            double lenghtMult = 12/vect.length();
            vect.mul(lenghtMult);
            
        	g2d.drawLine(x0, y0, (int)(x0+vect.x), (int)(y0+vect.y));
        	//vect.normalize().mul(0);
        	g2d.setColor(Color.red);
        	g2d.setStroke(new BasicStroke(1));
    	
            g2d.drawImage(craft.getImage(), craft.getX(), craft.getY(),this);

        }
        
        
        for (int i = 0; i < birds.size(); i++) {
        	Bird b = (Bird)birds.get(i);
            if (b.isVisible())
                g2d.drawImage(b.getImage(), b.getX(), b.getY(), this);
        }
        
        
        g2d.setColor(Color.WHITE);
        g2d.drawString("Enemies left: " + aliens.size(), 5, 15);
        g2d.drawString("Points/Cash: " + gamePoints, 5, 30);
        g2d.drawString("Arrows fired: " + craft.getArrowsFired(), 5, 45);
        
       	font = new Font("Helvetica", Font.BOLD, 20);
       	g.setFont(font);
        g.setColor(Color.RED);
        g.drawString("+ "+castle.getHealth(), 60, 365);
    }
    
    
    /**
     * Uses the specifications of the Button class to paint a button. 
     *
     * @param  g  the graphics componenet used to paint various elements of the stage
     */
    public void paintButton(Graphics g, Button b)
    {
    	g.setColor(b.getColor());
    	g.setFont(b.getFont());
    	g.fillRoundRect(b.getRect().x, b.getRect().y, b.getRect().width, b.getRect().height, 10, 10);
    	g.setColor(Color.WHITE);
    	g.drawString(b.getLabel(), b.x+5, b.y+b.h/2);
    }


    /**
     * This method is run after every frame of the game to check for certain conditions. 
     *
     * @param  e  the event that just occurred
     */
    public void actionPerformed(ActionEvent e) {

        if (aliens.size()==0 && !startStage) 
        {

        	

            stage++;
            inStageMenu = true;
            startStage = true;
      	 	buttons.get(1).setClicked(false);
      	 	buttons.get(2).setClicked(false);
      	 	
      	 	if(craft.usesPowerBar())
      	 		buttons.get(3).setClicked(false);
      	 	if(!craft.canDoubleFire())
      	 		buttons.get(4).setClicked(false);      	 	
      	 	if(!craft.getQuickFire())
          	 		buttons.get(5).setClicked(false);

        }
        
        if(castle.getHealth() <= 0)
        {
        	ingame = false;
        }

        ArrayList<Missile> ms = craft.getMissiles();

        for (int i = 0; i < ms.size(); i++) {
            Missile m = (Missile) ms.get(i);
            if(m.hitGround())
            	m.stop();
            if (m.isVisible()) 
                m.move();
            else ms.remove(i);
        }

        for (int i = 0; i < aliens.size(); i++) {
            Alien a = (Alien) aliens.get(i);
            if (a.isVisible()) 
                a.move();
            else aliens.remove(i);
        }
        
        for (int i = 0; i < birds.size(); i++) {
        	Bird b = (Bird) birds.get(i);
            if (b.isVisible()) 
                b.move();
            else birds.remove(i);
        }


        if(ingame && !inStageMenu && !startStage )  
        {
        	craft.move();
        	checkCollisions();
        }
        repaint();  
    }

    /**
     * Checks every object in the game for collisions after every frame and runs necessary actions.
     */
    public void checkCollisions() {

        Rectangle r3 = craft.getBounds();

        for (int j = 0; j<aliens.size(); j++) {
            Alien a = (Alien) aliens.get(j);
            Rectangle r2 = a.getBounds();

            if(a.getX()<=5)
            {
            	castle.enemyEntered();
            	a.setVisible(false);
            }
            if (r3.intersects(r2)) {
                //craft.setVisible(false);
                //a.setVisible(false);
                //ingame = false;
            }
        }

        ArrayList<Missile> ms = craft.getMissiles();

        for (int i = 0; i < ms.size(); i++) {
            Missile m = (Missile) ms.get(i);

            if(!m.hitGround())
            {
                Rectangle r1 = m.getBounds();
            	
                for (int j = 0; j<birds.size(); j++) {
                    Bird b = (Bird) birds.get(j);
                    Rectangle r4 = b.getBounds();

                    if (r1.intersects(r4)) {
                    	totalBirdsKilled++;
                    	gamePoints+=15;
                        m.setVisible(false);
                        b.wasHitBy(m);
                    }
                }
                    
                for (int j = 0; j<aliens.size(); j++) {
                    Alien a = (Alien) aliens.get(j);
                    Rectangle r2 = a.getBounds();

                    if (r1.intersects(r2)) {
                    	totalEnimiesKilled++;
                    	gamePoints+=5;
                        m.setVisible(false);
                        a.setVisible(false);
                    }
                }
            }
        }
    }

    /**
     * This class record key and mouse actions and runs the necessary results.
     */
    private class TAdapter extends KeyAdapter {

        public void keyReleased(KeyEvent e) {
            craft.keyReleased(e);
            
            int key = e.getKeyCode();

            if (key == KeyEvent.VK_SPACE) 
            {
                if(ingame)
                {
                	if(inStageMenu)
                		inStageMenu = false;
                	
                	else if(startStage)
                	{
                		startStage=false;
                		initEnemies();
                	}
                }
            }
        }
        
        public void keyPressed(KeyEvent e) {
            craft.keyPressed(e);
        }
    }
    

    private class CraftAdapter extends MouseAdapter {

    	public void mousePressed(MouseEvent e) {
           craft.mousePressed(e);
           for(int i=0; i<buttons.size(); i++)
        	   buttons.get(i).mousePressed(e);

           
        }

        public void mouseReleased(MouseEvent e) {
            craft.mouseReleased(e);

        }

    }

            


}
